snapshot: Implement gtk_snapshot_clips_rect()
authorBenjamin Otte <otte@redhat.com>
Thu, 17 Nov 2016 02:31:15 +0000 (03:31 +0100)
committerBenjamin Otte <otte@redhat.com>
Thu, 17 Nov 2016 02:33:50 +0000 (03:33 +0100)
And use this to cull widgets and gadgets that are completely outside the
clip region.

A potential optimization is to apply this clip region to cairo contexts
created with gtk_snapshot_append_cairo_node(), but for that we'd need to
apply the inverse matrix to the clip region, and that causes rounding
errors.

Plus, I hope that cairo drawing becomes exceedingly rare so it won't be
used for the whole widget factory like today (which might also explain
why no culling happens in the widget factory outside the header bar.

gtk/gtksnapshot.c
gtk/gtksnapshotprivate.h
gtk/gtkwidget.c

index a86df11d8967c37bab72734aa265c1f64a6eccf7..5733d85176eedec167ad5ec9b046dc4eb592c880 100644 (file)
@@ -55,6 +55,26 @@ gtk_snapshot_state_set_transform (GtkSnapshotState        *state,
                                   const graphene_matrix_t *transform)
 {
   graphene_matrix_init_from_matrix (&state->transform, transform);
+
+  state->world_is_valid = FALSE;
+}
+
+static const graphene_matrix_t *
+gtk_snapshot_state_get_world_transform (GtkSnapshotState *state)
+{
+  if (!state->world_is_valid)
+    {
+      if (state->parent)
+        graphene_matrix_multiply (gtk_snapshot_state_get_world_transform (state->parent),
+                                  &state->transform,
+                                  &state->world_transform);
+      else
+        graphene_matrix_init_from_matrix (&state->world_transform, &state->transform);
+
+      state->world_is_valid = TRUE;
+    }
+
+  return &state->world_transform;
 }
 
 void
@@ -140,34 +160,6 @@ gtk_snapshot_get_renderer (const GtkSnapshot *state)
   return state->renderer;
 }
 
-#if 0
-GskRenderNode *
-gtk_snapshot_create_render_node (const GtkSnapshot *state,
-                                 const char *name,
-                                 ...)
-{
-  GskRenderNode *node;
-
-  node = gsk_renderer_create_render_node (state->renderer);
-
-  if (name)
-    {
-      va_list args;
-      char *str;
-
-      va_start (args, name);
-      str = g_strdup_vprintf (name, args);
-      va_end (args);
-
-      gsk_render_node_set_name (node, str);
-
-      g_free (str);
-    }
-
-  return node;
-}
-#endif
-
 void
 gtk_snapshot_set_transform (GtkSnapshot             *snapshot,
                             const graphene_matrix_t *transform)
@@ -325,11 +317,38 @@ gtk_snapshot_push_cairo_node (GtkSnapshot            *state,
   return gsk_render_node_get_draw_context (node, state->renderer);
 }
 
+static void
+rectangle_init_from_graphene (cairo_rectangle_int_t *cairo,
+                              const graphene_rect_t *graphene)
+{
+  cairo->x = floorf (graphene->origin.x);
+  cairo->y = floorf (graphene->origin.y);
+  cairo->width = ceilf (graphene->origin.x + graphene->size.width) - cairo->x;
+  cairo->height = ceilf (graphene->origin.y + graphene->size.height) - cairo->y;
+}
+
 gboolean
 gtk_snapshot_clips_rect (GtkSnapshot           *snapshot,
                          const graphene_rect_t *bounds)
 {
-  return FALSE;
+  cairo_rectangle_int_t rect;
+
+  if (snapshot->state)
+    {
+      const graphene_matrix_t *world;
+      graphene_rect_t transformed;
+
+      world = gtk_snapshot_state_get_world_transform (snapshot->state);
+
+      graphene_matrix_transform_bounds (world, bounds, &transformed);
+      rectangle_init_from_graphene (&rect, &transformed);
+    }
+  else
+    {
+      rectangle_init_from_graphene (&rect, bounds);
+    }
+
+  return cairo_region_contains_rectangle (snapshot->clip_region, &rect) == CAIRO_REGION_OVERLAP_OUT;
 }
 
 void
index c9899d004f029ef70b12394c63ad19d4f0b8f740..ff9d1b62c0dc2605ec3a8b1fe14498f26c3eaa62 100644 (file)
@@ -30,6 +30,8 @@ struct _GtkSnapshotState {
   GskRenderNode         *node;
 
   graphene_matrix_t      transform;
+  graphene_matrix_t      world_transform;
+  guint                  world_is_valid : 1;
 };
 
 struct _GtkSnapshot {
index 7e4c56d56e8c29c8ed4e88cdb6a62e7a81d15a6a..4045e3f501ce2aa4317212aee5bcb21cea280338 100644 (file)
@@ -15657,6 +15657,8 @@ gtk_widget_snapshot (GtkWidget   *widget,
   gtk_widget_get_clip (widget, &clip);
   _gtk_widget_get_allocation (widget, &alloc);
   graphene_rect_init (&bounds, alloc.x - clip.x, alloc.y - clip.y, clip.width, clip.height);
+  if (gtk_snapshot_clips_rect (snapshot, &bounds))
+    return;
 
   /* Compatibility mode: if the widget does not have a render node, we draw
    * using gtk_widget_draw() on a temporary node